<template>
  <div class="transitionPage">
    <h3>过渡动画的四种触发方式：（外层用transition标签包裹）</h3>
    <h4>1.条件渲染 (使用 v-if)</h4>
    <h4>2.条件展示 (使用 v-show)</h4>
    <h4>3.动态组件</h4>
    <h4>4.根组件节点</h4>

    <h3>transition标签：</h3>
    <h4>1.name属性，class方式的前缀</h4>
    <h4>2.mode属性，过渡模式（常用值：out-in in-out）</h4>
    <h4>3.type属性，可以设置transition/animation，表示Vue监听的类型，以哪个时间为准</h4>
    <h4>4.appear属性，初始渲染的过渡</h4>

    <h3>transition-group标签：</h3>
    <h4>1.tag属性，用来指定包裹元素</h4>
    <h4>2.内部元素单元，必须有key属性</h4>
    <h4>3.内部元素单元，表现过渡效果</h4>
    <h4>4.可以使用v-move表现列表的移动过渡</h4>
    <h4>name、type、appear同上</h4>
    <h4>不存在mode</h4>

    <h3>过渡动画实现的两种方式：</h3>
    <h4>1.class方式：</h4>
    <h5>class生命周期：</h5>
    <h5>（1）from 进入/离开前</h5>
    <h5>（2）to 进入/离开过程中</h5>
    <h5>（3）enter-active 进入前 + 进入过程中</h5>
    <h5>（4）leave-active 离开过程中</h5>
    <h5>示例一：transition标签的class样式</h5>
    <h5>样式作用流程：enter-from黄 enter-active蓝 本色红 leave-from黑 leave-to蓝</h5>
    <div class="tempClass1">
      <button @click="tempClassShow1 = !tempClassShow1">Toggle render</button>
      <transition name="slide-fade" appear>
        <div v-show="tempClassShow1" class="content">hello</div>
      </transition>
    </div>
    <h5>示例二：transition标签class样式 + animation样式</h5>
    <h5 class="tips">tips1：transition标签的class样式，避免和animation内的样式有冲突（例如transform）</h5>
    <h5 class="tips">tips2：transition标签的type属性，可以设置transition/animation，表示Vue监听的类型，以哪个时间为准</h5>
    <div class="tempClass2">
      <button @click="tempClassShow2 = !tempClassShow2">Toggle show</button>
      <transition name="bounce" type="animation">
        <p v-show="tempClassShow2" class="content">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris facilisis enim libero, at lacinia diam fermentum id. Pellentesque habitant morbi
          tristique senectus et netus.
        </p>
      </transition>
    </div>
    <h4>2.js钩子方式：</h4>
    <h5>js钩子生命周期：</h5>
    <h5>（1）@before-enter 进入前</h5>
    <h5>（2）@enter 进入过程中</h5>
    <h5>（3）@after-enter 进入后</h5>
    <h5>（4）@enter-cancelled 进入取消</h5>
    <h5>（5）@before-leave 离开前</h5>
    <h5>（6）@leave 离开过程中</h5>
    <h5>（7）@after-leave 离开后</h5>
    <h5>（8）@leave-cancelled 离开取消</h5>
    <h5 class="tips">tips：:css="false"，忽略css（提升性能 排除css的影响）</h5>
    <h5>示例一：transition标签js钩子 + gsap动画库</h5>
    <div class="tempJS1">
      <button @click="tempJSShow1 = !tempJSShow1">Toggle</button>
      <transition @before-enter="beforeEnter" @enter="enter" @leave="leave" @after-leave="afterLeave" :css="false">
        <div v-show="tempJSShow1" class="content">js钩子</div>
      </transition>
    </div>

    <h3>应用：列表过渡</h3>
    <h4>1.列表的进入/离开/移动过渡：(class方式)</h4>
    <h5>列表的移动过渡的实现：</h5>
    <h5>（1）元素自身的transition样式 / v-move中transition样式</h5>
    <h5 class="tips">tips：移动过渡的元素样式不能是inline</h5>
    <h5 class="tips">tips：移动过渡的元素样式，自身使用transition / v-move中使用transition</h5>
    <h5 class="tips">tips：离开的移动过渡BUG需要添加样式 .v-leave-active { position: absolute; }</h5>
    <div class="tempList1">
      <button @click="add">Add</button>
      <button @click="remove">Remove</button>
      <button @click="shuffle">Shuffle</button>
      <transition-group name="list" tag="div" appear>
        <span v-for="item in items" :key="item" class="list-item">
          {{ item }}
        </span>
      </transition-group>
    </div>
    <h4>2.列表元素的依次延迟过渡：(js钩子 + gsap动画库)</h4>
    <h5 class="tips">tips：读取元素属性的值，作为gsap动画的参数，控制元素的延时执行</h5>
    <div class="tempList2">
      <input v-model="query" />
      <transition-group name="staggered-fade" tag="ul" :css="false" @before-enter="listBeforeEnter" @enter="listEnter" @leave="listLeave">
        <li v-for="(item, index) in computedList" :key="item.msg" :data-index="index">
          {{ item.msg }}
        </li>
      </transition-group>
    </div>

    <h3>过渡动画的复用：(使用slot)</h3>
    <h5 class="tips">tips：slot标签获取组件中的控制显示的变量，给到template标签，给到需要动画的组件</h5>
    <transitionModel>
      <template #="subProps">
        <subComponent :show="subProps.show"></subComponent>
      </template>
    </transitionModel>

    <h3>过渡动画的动态控制：</h3>
    <h4>动态控制的方式：</h4>
    <h4>1.通过transition标签的name属性，切换class前缀</h4>
    <h4>2.通过transition标签的js钩子函数，切换不同的变量</h4>

    <h3>过渡动画的状态过渡：</h3>
    <h4>1.gsap动画库方式：</h4>
    <h5 class="tips">tips：利用了gsap动画函数，动态改变值的方式，响应式显示出来</h5>
    <div class="statusTransition1">
      <input v-model.number="number" type="number" step="20" />
      <p>{{ animatedNumber }}</p>
    </div>
    <h4>2.gsap动画库方式(组件版)：</h4>
    <input v-model.number="firstNumber" type="number" step="20" /> + <input v-model.number="secondNumber" type="number" step="20" /> = {{ result }}
    <p>
      <AnimatedInteger :value="firstNumber"></AnimatedInteger> + <AnimatedInteger :value="secondNumber"></AnimatedInteger> =
      <AnimatedInteger :value="result"></AnimatedInteger>
    </p>
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
import gsap from "gsap";
import _ from "lodash";
import transitionModel from "./components/transitionModel.vue";
import subComponent from "./components/subComponent.vue";
import AnimatedInteger from "./components/animatedInteger.vue";
export default defineComponent({
  components: {
    transitionModel,
    subComponent,
    AnimatedInteger,
  },
  emits: [],
  data() {
    return {
      tempClassShow1: true,
      tempClassShow2: true,
      tempJSShow1: false,
      items: [1, 2, 3, 4, 5, 6, 7, 8, 9],
      nextNum: 10,
      query: "",
      list: [{ msg: "Bruce Lee" }, { msg: "Jackie Chan" }, { msg: "Chuck Norris" }, { msg: "Jet Li" }, { msg: "Kung Fury" }],
      number: 0,
      tweenedNumber: 0,
      firstNumber: 20,
      secondNumber: 40,
    };
  },
  computed: {
    computedList() {
      var vm = this;
      return this.list.filter((item) => {
        return item.msg.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1;
      });
    },
    animatedNumber() {
      console.log("this.tweenedNumber---", this.tweenedNumber);
      return this.tweenedNumber.toFixed(0);
    },
    result() {
      return this.firstNumber + this.secondNumber;
    },
  },
  watch: {
    number(newValue) {
      console.log("newValue---", newValue);
      gsap.to(this.$data, { duration: 0.5, tweenedNumber: newValue });
    },
  },
  methods: {
    beforeEnter(el) {
      gsap.set(el, {
        scaleX: 0.8,
        scaleY: 1.2,
      });
    },
    enter(el, done) {
      gsap.to(el, {
        duration: 1,
        scaleX: 1.5,
        scaleY: 0.7,
        opacity: 1,
        x: 150,
        ease: "elastic.inOut(2.5, 1)",
        onComplete: done,
      });
    },
    leave(el, done) {
      gsap.to(el, {
        duration: 0.7,
        scaleX: 1,
        scaleY: 1,
        x: 300,
        ease: "elastic.inOut(2.5, 1)",
      });
      gsap.to(el, {
        duration: 0.2,
        delay: 0.5,
        opacity: 0,
        onComplete: done,
      });
    },
    afterLeave(el) {
      gsap.set(el, {
        scaleX: 0.8,
        scaleY: 1.2,
        x: 0,
      });
    },
    randomIndex() {
      return Math.floor(Math.random() * this.items.length);
    },
    add() {
      this.items.splice(this.randomIndex(), 0, this.nextNum++);
    },
    remove() {
      this.items.splice(this.randomIndex(), 1);
    },
    shuffle() {
      this.items = _.shuffle(this.items);
    },
    listBeforeEnter(el) {
      el.style.opacity = 0;
      el.style.height = 0;
    },
    listEnter(el, done) {
      gsap.to(el, {
        opacity: 1,
        height: "1.6em",
        delay: el.dataset.index * 0.15,
        onComplete: done,
      });
    },
    listLeave(el, done) {
      gsap.to(el, {
        opacity: 0,
        height: 0,
        delay: el.dataset.index * 0.15,
        onComplete: done,
      });
    },
  },
});
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style lang="scss" scoped>
.transitionPage {
  text-align: left;
  margin-left: 160px;
  h3 {
    color: skyblue;
    margin: 40px 0 0;
  }
  .tips {
    color: $myRedColor;
  }
  .tempClass1 {
    height: 55px;
    .content {
      width: 50px;
      color: red;
    }

    // 进入前和进入过程中都起效，进入后移除（enter-active比较特殊，包含了进入前）
    .slide-fade-enter-active {
      transition: all 4s ease-in;
      color: blue;
    }
    // 进入前起效，然后移除（要放入进入过程中的下面，防止进入前被覆盖）
    .slide-fade-enter-from {
      transform: translateX(40px);
      color: yellow;
    }
    // 进入过程中都起效，进入后移除
    // .slide-fade-enter-to {
    //   color: green;
    // }

    // 离开前起效，然后移除
    .slide-fade-leave-from {
      color: black;
    }
    // 离开过程中起效，离开后移除
    .slide-fade-leave-active {
      transition: all 4s ease-out;
      color: yellow;
    }

    // 离开过程中起效，离开后移除 同leave-active一样
    .slide-fade-leave-to {
      transform: translateX(40px);
      color: blue;
    }
  }
  .tempClass2 {
    height: 150px;
    .content {
      color: red;
      width: 400px;
    }
    .bounce-enter-active {
      // transition: all 2s ease-in;
      animation: bounce-in 2s;
    }
    .bounce-leave-active {
      // transition: all 2s ease-out;
      animation: bounce-in 2s reverse;
    }
    .bounce-enter-from,
    .bounce-leave-to {
      color: blue;
    }
    @keyframes bounce-in {
      0% {
        transform: scale(0);
      }
      50% {
        transform: scale(1.25);
      }
      100% {
        transform: scale(1);
      }
    }
  }
  .tempJS1 {
    height: 60px;
    .content {
      width: 100px;
      background: #000;
      color: #fff;
    }
  }
  .tempList1 {
    height: 80px;
    .list-item {
      // transition: transform 1s ease;
      display: inline-block;
      margin-right: 10px;
    }
    .list-enter-active,
    .list-leave-active {
      transition: all 1s ease;
    }

    .list-enter-from,
    .list-leave-to {
      opacity: 0;
      transform: translateY(30px);
    }

    .list-move {
      transition: transform 1s ease;
    }
    // 元素移除时的移动过渡，需要添加下面的补充样式
    .list-leave-active {
      position: absolute;
    }
  }
  .tempList2 {
    height: 160px;
  }
}
</style>
